home *** CD-ROM | disk | FTP | other *** search
/ CD ROM Paradise Collection 4 / CD ROM Paradise Collection 4 1995 Nov.iso / program / recio212.zip / rget.c < prev    next >
C/C++ Source or Header  |  1995-01-29  |  23KB  |  623 lines

  1. /*****************************************************************************
  2.    MODULE: rget.c
  3.   PURPOSE: recio input functions
  4. COPYRIGHT: (C) 1994-1995, William Pierpoint
  5.  COMPILER: Borland C Version 3.1
  6.        OS: MSDOS Version 6.2
  7.   VERSION: 2.12
  8.   RELEASE: January 29, 1995
  9. *****************************************************************************/
  10.  
  11. #include <ctype.h>
  12. #include <errno.h>
  13. #include <limits.h>
  14. #include <stdio.h>
  15. #include <stdlib.h>
  16. #include <string.h>
  17.  
  18. #include "recio.h"
  19.  
  20. extern int _risready(REC *rp, int mode);
  21. extern int _rmoderror(REC *rp, int mode);
  22. extern void _rsetexitfn(REC *rp);
  23.  
  24. /* private macros */
  25. #define RECBUFSIZ_MIN 2         /* min one character and new line */
  26. #define FLDBUFSIZ_MIN 1         /* min one character */
  27.  
  28. #define RECBUFSIZE    max(RECBUFSIZ, RECBUFSIZ_MIN)
  29. #define FLDBUFSIZE    max(FLDBUFSIZ, FLDBUFSIZ_MIN)
  30.  
  31. #define rcol(rp)         ((rp)->r_colno)
  32. #define rflags(rp)       ((rp)->r_flags)
  33. #define rfd(rp)          ((rp)->r_fd)
  34. #define rfp(rp)          ((rp)->r_fp)
  35. #define rreclen(rp)      ((rp)->r_reclen)
  36. #define rrecsiz(rp)      ((rp)->r_recsiz)
  37. #define rfldsiz(rp)      ((rp)->r_fldsiz)
  38. #define rfldch(rp)       ((rp)->r_fldch)
  39. #define rtxtch(rp)       ((rp)->r_txtch)
  40.  
  41. /****************************************************************************/
  42. static int                   /* return error number (0=no error)            */
  43.     _rsetfldsiz(             /* set field buffer size                       */
  44.         REC   *rp,           /* record pointer                              */
  45.         size_t fldsiz)       /* field buffer size                           */
  46. /****************************************************************************/
  47. {
  48.     int errnum=0;            /* error number */
  49.     char *fldp;              /* pointer to new field buffer */
  50.  
  51.     /* if no memory allocated to field buffer */
  52.     if (!rflds(rp)) {
  53.  
  54.         /* determine minimum size of field buffer */
  55.         fldsiz = max(fldsiz, FLDBUFSIZE);
  56.  
  57.         /* initially allocate memory for field buffer */
  58.         do {
  59.             fldp = (char *) calloc(fldsiz+1, sizeof(char));
  60.             if (!fldp) {
  61.                 errnum = rseterr(rp, R_ENOMEM);
  62.                 if (errnum) goto done;
  63.             }
  64.         } while (!fldp);
  65.         rflds(rp) = fldp;
  66.         rfldsiz(rp) = fldsiz;
  67.         _rsetexitfn(rp);
  68.  
  69.     /* if field buffer needs to be larger */
  70.     } else if (fldsiz > rfldsiz(rp)) {
  71.  
  72.         /* reallocate memory for field buffer */
  73.         do {
  74.             fldp = (char *) realloc(rflds(rp), fldsiz+1);
  75.             if (!fldp) {
  76.                 errnum = rseterr(rp, R_ENOMEM);
  77.                 if (errnum) goto done;
  78.             }
  79.         } while (!fldp);
  80.         rflds(rp) = fldp;
  81.         rfldsiz(rp) = fldsiz;
  82.     }
  83.  
  84. done:
  85.     return errnum;
  86. }
  87.  
  88. /****************************************************************************/
  89. static int                   /* return error number (0=no error)            */
  90.     _rsetrecsiz(             /* set record buffer size                      */
  91.         REC   *rp,           /* record pointer                              */
  92.         size_t recsiz)       /* record buffer size                          */
  93. /****************************************************************************/
  94. {
  95.     int errnum=0;            /* error number */
  96.     char *recp;              /* pointer to new record buffer */
  97.  
  98.     /* if no memory allocated to field buffer */
  99.     if (!rrecs(rp)) {
  100.  
  101.         /* determine minimum size of record buffer */
  102.         recsiz = max(recsiz, RECBUFSIZE);
  103.  
  104.         /* initially allocate memory for record buffer */
  105.         do {
  106.             recp = (char *) calloc(recsiz+1, sizeof(char));
  107.             if (!recp) {
  108.                 errnum = rseterr(rp, R_ENOMEM);
  109.                 if (errnum) goto done;
  110.             }
  111.         } while (!recp);
  112.         rrecs(rp) = recp;
  113.         rrecsiz(rp) = recsiz;
  114.         _rsetexitfn(rp);
  115.  
  116.     /* if record buffer needs to be larger */
  117.     } else if (recsiz > rrecsiz(rp)) {
  118.  
  119.         /* reallocate memory for record buffer */
  120.         do {
  121.             recp = (char *) realloc(rrecs(rp), recsiz+1);
  122.             if (!recp) {
  123.                 errnum = rseterr(rp, R_ENOMEM);
  124.                 if (errnum) goto done;
  125.             }
  126.         } while (!recp);
  127.         rrecs(rp) = recp;
  128.         rrecsiz(rp) = recsiz;
  129.     }
  130.  
  131. done:
  132.     return errnum;
  133. }
  134.  
  135. /****************************************************************************/
  136. static int                   /* return !0 on match                          */
  137.     risfldch(                /* is character the field separator character? */
  138.         REC *rp,             /* record pointer                              */
  139.         int  ch)             /* character to test                           */
  140. /****************************************************************************/
  141. {
  142.     int ismatch=0;           /* return 0 if no match */
  143.  
  144.     if (isascii(ch)) { 
  145.         if (rfldch(rp) == ' ') {
  146.             ismatch = isspace(ch);
  147.         } else {
  148.             ismatch = (!(ch - rfldch(rp)));
  149.         }
  150.     }
  151.     return ismatch;
  152. }
  153.  
  154. /****************************************************************************/
  155. static int                   /* return !0 on match                          */
  156.     ristxtch(                /* is character the text delimiter character?  */
  157.         REC *rp,             /* record pointer                              */
  158.         int  ch)             /* character to test                           */
  159. /****************************************************************************/
  160. {
  161.     int ismatch=0;           /* return 0 if no match */
  162.  
  163.     if (isascii(ch)) { 
  164.         if (rtxtch(rp) == ' ') {
  165.             ismatch = isspace(ch);
  166.         } else {
  167.             ismatch = (!(ch - rtxtch(rp)));
  168.         }
  169.     }
  170.     return ismatch;
  171. }
  172.  
  173. /****************************************************************************/
  174. static size_t                /* return length of field                      */
  175.     _rfldlen(                /* get length of field                         */
  176.         REC *rp)             /* record pointer                              */
  177. /****************************************************************************/
  178. {
  179.     size_t len=0;            /* length of field (0=missing field) */
  180.     size_t col;              /* column location */
  181.     size_t co;               /* temporary column location */
  182.     int qstate=0;            /* nested quoted text state (0=off; 1=on) */
  183.  
  184.     /* clear quoted text char flag */
  185.     rflags(rp) &= ~_R_TXT;
  186.  
  187.     /* skip past any leading whitespace */
  188.     for (col=rcol(rp); col < rreclen(rp); col++) {
  189.         if (!isspace(rrecs(rp)[col])) break;
  190.     }
  191.  
  192.     /* is first non-whitespace character the txtch? */
  193.     if (ristxtch(rp, rrecs(rp)[col])) { /* yes, quoted text */
  194.         rflags(rp) |= _R_TXT;           /* set quoted text char flag  */
  195.         if (risfldch(rp, ' ')) {        /* fldch == ' '; txtch != ' ' */
  196.             /* skip over characters that are not txtch */
  197.             for (col++; col < rreclen(rp); col++) {
  198.                 /* if txtch, see if end-of-field */
  199.                 if (ristxtch(rp, rrecs(rp)[col])) {
  200.                     /* don't end field within any nested quoted text */
  201.                     if (ristxtch(rp, '"')) {
  202.                         qstate = !qstate;
  203.                         if (!qstate) continue;
  204.                     }
  205.                     /* if whitespace follows txtch, then end-of-field */
  206.                     if (isspace(rrecs(rp)[col+1])) {
  207.                         /* skip to end of trailing whitespace */
  208.                         for (col++; col < rreclen(rp); col++) {
  209.                             if (!isspace(rrecs(rp)[col])) {
  210.                                 col--;
  211.                                 break;
  212.                             }
  213.                         }
  214.                         break;
  215.                     }
  216.                 }
  217.             }
  218.         } else {                  /* fldch != ' '; txtch != ' ' */
  219.             /* skip over characters that are not txtch */
  220.             for (col++; col < rreclen(rp); col++) {
  221.                 /* if txtch, see if end-of-field */
  222.                 if (ristxtch(rp, rrecs(rp)[col])) {
  223.                     /* don't end field within any nested quoted text */
  224.                     if (ristxtch(rp, '"')) {
  225.                         qstate = !qstate;
  226.                         if (!qstate) continue;
  227.                     }
  228.                     /* skip any whitespace */
  229.                     for (co=col+1; co < rreclen(rp); co++) {
  230.                         if (!isspace(rrecs(rp)[co])) break;
  231.                     }
  232.                     /* if fldch, then end-of-field */
  233.                     if (risfldch(rp, rrecs(rp)[co])) {
  234.                         col = co;
  235.                         break;
  236.                     }
  237.                 }
  238.             }
  239.         }
  240.     } else {                      /* else not quoted text */
  241.         if (risfldch(rp, ' ')) {  /* fldch == ' '; txtch == ' ' */
  242.             /* skip non-whitespace */
  243.             for (; col < rreclen(rp); col++) {
  244.                 if (isspace(rrecs(rp)[col])) break;
  245.             }
  246.             /* skip to end of trailing whitespace */
  247.             for (; col < rreclen(rp); col++) {
  248.                 if (!isspace(rrecs(rp)[col])) {
  249.                     col--;
  250.                     break;
  251.                 }
  252.             }
  253.         } else {                 /* fldch != ' '; txtch == ' ' */
  254.             /* skip over characters until fldch reached */
  255.             for (; col < rreclen(rp); col++) {
  256.                 if (risfldch(rp, rrecs(rp)[col])) break;
  257.             }
  258.         }
  259.     }
  260.     
  261.     /* get length of field */
  262.     if (rcol(rp) < rreclen(rp)) {
  263.         len = col - rcol(rp) + 1;
  264.     }
  265.     return len;
  266. }
  267.  
  268. /****************************************************************************/
  269. static int                   /* return error state (0=no error; EOF=error)  */
  270.     _rskipfld(               /* skip to the next field                      */
  271.         REC   *rp,           /* record pointer                              */
  272.         size_t len)          /* length of field if known, 0 if unknown      */
  273. /****************************************************************************/
  274. {
  275.     int err=0;          /* error state (0=no error; EOF=past end-of-record) */
  276.  
  277.     /* make sure first record is read from file */
  278.     if (!rrecno(rp) && !rgetrec(rp)) goto done;
  279.  
  280.     /* if length of field is unknown */
  281.     if (!len) {
  282.         /* determine length */
  283.         len=_rfldlen(rp);
  284.     }
  285.     
  286.     /* if field delimiter is whitespace */
  287.     if (risfldch(rp, ' ')) {
  288.         /* if not at end of record */
  289.         if (rcol(rp) < rreclen(rp)) {
  290.             /* move to next field */
  291.             rcol(rp) += max(len, 1);
  292.         } else {
  293.             /* cannot move beyond end of record */
  294.             err = EOF;
  295.         }
  296.     } else {
  297.         /* allow for empty field past last field delimiter */
  298.         if (rcol(rp) <= rreclen(rp)) {
  299.             /* move to next field */
  300.             rcol(rp) += max(len, 1);
  301.         } else {
  302.             /* cannot move beyond end of record */
  303.             err = EOF;
  304.         }
  305.     }
  306.     rfldno(rp)++;
  307.  
  308. done:
  309.     return err;
  310. }
  311.  
  312. /****************************************************************************/
  313. char *                       /* return pointer to field buffer (NULL=error) */
  314.     _rfldstr(                /* copy field from record to field buffer      */
  315.         REC   *rp,           /* record pointer                              */
  316.         size_t len)          /* length of field if known; 0 if unknown      */
  317. /****************************************************************************/
  318. {
  319.     char  *fldp=NULL;        /* pointer to field buffer (NULL=error) */
  320.     size_t fldlen=len;       /* computed length of field */
  321.  
  322.     /* make sure first record is read from file */
  323.     if (!rrecno(rp) && !rgetrec(rp)) goto done;
  324.  
  325.     /* if character delimited field, compute length */
  326.     if (!fldlen) {
  327.         fldlen=_rfldlen(rp);
  328.  
  329.     /* if column delimited field, avoid overflow */
  330.     } else if (rcol(rp) > rreclen(rp)) {
  331.         fldlen = 0;
  332.     }
  333.     
  334.     /* ensure field buffer has sufficient memory */
  335.     if (_rsetfldsiz(rp, fldlen)) goto done;
  336.  
  337.     /* copy field from record buffer to field buffer */
  338.     /* note: a missing field results in an empty string */
  339.     strncpy(rflds(rp), rrecs(rp)+rcol(rp), fldlen);
  340.     rflds(rp)[fldlen] = '\0';
  341.  
  342.     /* set up for next field */
  343.     _rskipfld(rp, max(fldlen, 1));
  344.  
  345.     /* if character delimited field, trim delimiters from field buffer */
  346.     if (!len) {
  347.         /* trim fldch */
  348.         scntrimends(rflds(rp), rfldch(rp), 1);
  349.  
  350.         /* if whitespace field delimiter, trim whitespace */
  351.         if (risfldch(rp, ' ')) {
  352.             strims(rflds(rp));
  353.         }
  354.         
  355.         /* if quoted text, trim txtch */
  356.         if (ristxtfld(rp)) {
  357.             strims(rflds(rp));
  358.             scntrims(rflds(rp), rtxtch(rp), 1);
  359.         }
  360.     }
  361.  
  362.     /* assign return pointer to field buffer */
  363.     fldp = rflds(rp);
  364.  
  365. done:
  366.     return fldp;
  367. }
  368.  
  369. /****************************************************************************/
  370. char *                       /* return ptr to rec buffer (NULL=err or eof)  */
  371.     rgetrec(                 /* read next line from file into record buffer */
  372.         REC *rp)             /* record pointer                              */
  373. /****************************************************************************/
  374. {
  375.     char *retp=NULL;         /* return pointer (NULL=error or eof) */
  376.     char str[FLDBUFSIZE+1];  /* temporary string */
  377.  
  378.  
  379.     if (_risready(rp, R_READ)) {
  380.  
  381.         /* initially allocate memory for record buffer */
  382.         if (!rrecs(rp)) {
  383.             if (_rsetrecsiz(rp, RECBUFSIZE)) goto done;
  384.         }
  385.  
  386.         /* for each new record */
  387.         rfldno(rp) = 0;
  388.         rcol(rp) = 0;
  389.         rrecno(rp)++;
  390.         rreclen(rp) = 0;
  391.         *rrecs(rp) = '\0';
  392.  
  393.         /* if at end of file, skip reading from file */
  394.         if (reof(rp)) goto done;
  395.  
  396.         /* get next line from file into record buffer */
  397.         if (!fgets(rrecs(rp), rrecsiz(rp), rfp(rp))) {
  398.             /* set end-of-file indicator if no more records */
  399.             rflags(rp) |= _R_EOF;
  400.             goto done;
  401.         }
  402.         rreclen(rp) = strlen(rrecs(rp));
  403.  
  404.         /* if line longer than record buffer, extend record buffer */
  405.         while (rrecs(rp)[rreclen(rp)-1] != '\n') {
  406.             if (!fgets(str, FLDBUFSIZE+1, rfp(rp))) break;
  407.             if (_rsetrecsiz(rp, rrecsiz(rp) + FLDBUFSIZE)) goto done;
  408.             strncat(rrecs(rp), str, FLDBUFSIZE);
  409.             rreclen(rp) = strlen(rrecs(rp));
  410.         }
  411.  
  412.         /* trim end of record */
  413.         sctrimends(rrecs(rp), '\n');
  414.         rreclen(rp) = strlen(rrecs(rp));
  415.  
  416.         /* point retp to record buffer */
  417.         retp = rrecs(rp);
  418.     }
  419. done:
  420.     return retp;
  421. }
  422.  
  423. /****************************************************************************/
  424. void                         /* returns nothing                             */
  425.     rsetrecsiz(              /* set record buffer size                      */
  426.         REC   *rp,           /* record pointer                              */
  427.         size_t recsiz)       /* record buffer size                          */
  428. /****************************************************************************/
  429. {
  430.     if (_risready(rp, R_READ)) {
  431.         _rsetrecsiz(rp, recsiz);
  432.     }
  433. }
  434.  
  435. /****************************************************************************/
  436. void                         /* returns nothing                             */
  437.     rsetfldsiz(              /* set field buffer size                       */
  438.         REC   *rp,           /* record pointer                              */
  439.         size_t fldsiz)       /* field buffer size                           */
  440. /****************************************************************************/
  441. {
  442.     if (_risready(rp, R_READ)) {
  443.         _rsetfldsiz(rp, fldsiz);
  444.     }
  445. }
  446.  
  447. /****************************************************************************/
  448. void                         /* returns nothing                             */
  449.     rsetrecstr(              /* copy string to record buffer; clear errors  */
  450.         REC  *rp,            /* record pointer                              */
  451.   const char *s)             /* pointer to string                           */
  452. /****************************************************************************/
  453. {
  454.     size_t recsiz;           /* required record buffer size */
  455.  
  456.     if (risvalid(rp)) {
  457.         if (!_rmoderror(rp, R_READ)) {
  458.             if (s) {
  459.                 /* ensure record buffer is large enough for string */
  460.                 recsiz = strlen(s);
  461.                 if (recsiz > rrecsiz(rp)) {
  462.                     if (_rsetrecsiz(rp, recsiz)) goto done;
  463.                 }
  464.             
  465.                 /* copy string to record buffer */
  466.                 if (s != rrecs(rp)) strcpy(rrecs(rp), s);
  467.     
  468.                 /* prepare stream to read */
  469.                 rclearerr(rp);
  470.                 rfldno(rp) = 0;
  471.                 rcol(rp) = 0;
  472.                 rreclen(rp) = recsiz;
  473.         
  474.             } else {
  475.                 rseterr(rp, R_EINVAL);
  476.             }
  477.         }
  478.     } else {
  479.         rseterr(NULL, EINVAL);
  480.     }
  481. done:
  482. }
  483.  
  484. /****************************************************************************/
  485. void                         /* returns nothing                             */
  486.     rsetfldstr(              /* copy string into field buffer; clear errors */
  487.         REC  *rp,            /* record pointer                              */
  488.   const char *s)             /* pointer to string                           */
  489. /****************************************************************************/
  490. {
  491.     size_t fldsiz;           /* required field buffer size */
  492.  
  493.     if (risvalid(rp)) {
  494.         if (!_rmoderror(rp, R_READ)) {
  495.             if (s) {
  496.                 /* ensure field buffer is large enough for string */
  497.                 fldsiz = strlen(s);
  498.                 if (fldsiz > rfldsiz(rp)) {
  499.                     if (_rsetfldsiz(rp, fldsiz)) goto done;
  500.                 }
  501.             
  502.                 /* copy string to field buffer */
  503.                 strcpy(rflds(rp), s);
  504.  
  505.                 /* clear away any errors */
  506.                 rclearerr(rp);
  507.  
  508.             } else {
  509.                 rseterr(rp, R_EINVAL);
  510.             }
  511.         }
  512.     } else {
  513.         rseterr(NULL, EINVAL);
  514.     }
  515. done:
  516. }
  517.  
  518. /****************************************************************************/
  519. unsigned                     /* return number fields skipped                */
  520.     rskipnfld(               /* skip over next number of fields             */
  521.         REC     *rp,         /* record pointer                              */
  522.         unsigned num)        /* number of fields to skip over               */
  523. /****************************************************************************/
  524. {
  525.     unsigned count=0;        /* actual number of fields skipped */
  526.  
  527.     if (_risready(rp, R_READ)) {
  528.  
  529.         /* count number of fields to skip */
  530.         while (count < num) {
  531.             /* but don't count past end of record */
  532.             if (_rskipfld(rp, 0)) break;
  533.             count++;
  534.         }
  535.     }
  536.     return count;
  537. }
  538.  
  539. /****************************************************************************/
  540. void                         /* returns nothing                             */
  541.     _rgetfldpos(             /* get field position                          */
  542.         REC    *rp,          /* record pointer                              */
  543.         rpos_t *pos)         /* pointer to field position                   */
  544. /****************************************************************************/
  545. {
  546.     if (_risready(rp, R_READ)) {
  547.         rfd(pos) = rfd(rp);
  548.         rfldno(pos) = rfldno(rp);
  549.         rcol(pos) = rcol(rp);
  550.         rrecno(pos) = rrecno(rp);
  551.     }
  552. }
  553.  
  554. /****************************************************************************/
  555. void                         /* returns nothing                             */
  556.     _rsetfldpos(             /* set field position                          */
  557.         REC    *rp,          /* record pointer                              */
  558.   const rpos_t *pos)         /* pointer to field position                   */
  559. /****************************************************************************/
  560. {
  561.     if (_risready(rp, R_READ)) {
  562.         if (rfd(pos)==rfd(rp) && rrecno(pos)==rrecno(rp)) {
  563.             rfldno(rp) = rfldno(pos);
  564.             rcol(rp) = rcol(pos);
  565.         } else {
  566.             rseterr(rp, R_EINVAL);
  567.         }
  568.     }
  569. }
  570.  
  571. /****************************************************************************/
  572. unsigned                     /* return number of fields in current record   */
  573.     rnumfld(                 /* number of fields in current record          */
  574.         REC *rp)             /* record pointer                              */
  575. /****************************************************************************/
  576. {
  577.     unsigned num=0;          /* return number of fields in current record */
  578.     rpos_t pos;              /* field position */
  579.  
  580.     if (_risready(rp, R_READ)) {
  581.         /* store current field information */
  582.         rgetfldpos(rp, pos);
  583.  
  584.         /* get number of fields from beginning of record */
  585.         rfldno(rp) = 0;
  586.         rcol(rp) = 0;
  587.         num = rskipnfld(rp, UINT_MAX);
  588.  
  589.         /* restore field information */
  590.         rsetfldpos(rp, pos);
  591.     }
  592.     return num;
  593. }
  594.  
  595. /****************************************************************************/
  596. unsigned long                /* return unsigned long                        */
  597.     str2ul(                  /* convert string to unsigned long             */
  598.         const char  *nptr,   /* pointer to string to convert                */
  599.               char **endptr, /* pointer to conversion leftover string       */
  600.               int    base)   /* base (radix) of number                      */
  601. /****************************************************************************/
  602. /* note: unlike strtoul, str2ul tests for a negative number */
  603. {
  604.     unsigned long ul=0UL;    /* result to return */
  605.     const char   *np=nptr;   /* pointer to string */
  606.  
  607.     /* skip over white space */
  608.     while (isspace(*np)) np++;
  609.     
  610.     /* if first non-white space is a minus sign */
  611.     if (*np == '-') {
  612.         
  613.         /* position endptr at the minus sign */
  614.         if (endptr) *endptr = (char *) np;
  615.  
  616.     } else {
  617.  
  618.         ul = strtoul(nptr, endptr, base);
  619.  
  620.     } 
  621.     return ul;
  622. }
  623.